import {Promise} from 'es6-promise';
import {Magics} from "../core/magics";
import {AuditLog} from "../core/types";
import * as utils from "../core/utils";
import {ErrCode} from "../core/error.code";
import {Collection, ObjectID} from "mongodb";
import {BaseModel} from "../core/base.model";
import {
    FindParam,
    CountParam,
    InsertParam,
    UpdateParam,
    FindOneParam,
    AggregateParam,
} from "../core/params";
import {
    Role,
    CursorType,
    OrderVendorDisplayStatus,
    PayType,
    PPEDepartType,
    TransType
} from "../core/defines";

export interface OrderUserInfo {
    id: ObjectID,
    name: string,
    phone?: string,
    telephone?: string,
    loc?: {
        prov: string,
        city: string,
        dist: string
    } | Object,
    address?: string
}

export interface OrderProduct {
    id: ObjectID,
    thumb: string,
    name: string,
    cate: string,
    sub_cate: string,
    price: number,
    num: number,
    amount: number,
    ship_free: boolean,
    log?: string,
}

export interface Voucher {
    id: ObjectID,
    detail: any,
    amount: number,
    start: Date,
    end: Date
}

export interface Order {
    _id?: ObjectID,
    buyer: {
        id: ObjectID,
        log?: string,
        tooken?: string,
        wechat?: string,
    },
    vendor?: OrderUserInfo,
    trans_id?: string,
    order_id?: string,
    order_no?: string,
    trans: {
        products: Array<OrderProduct>,
        favorable?: {
            voucher: Array<Voucher>,
            amount: number
        },
        pay_type?: PayType,
        amount?: number,
        payment?: number,
        buyer_pay?: number,
        pay_time?: Date,
        repay_time?: Date,
        log?: string,
    },
    delivery?: {
        time?: Date,
        receipt?: Date,
        amount?: number,
        buyer?: OrderUserInfo
    },
    deleted: {
        buyer: boolean,
        vendor: boolean,
    },
    audit_log ?: Array<AuditLog>,
    status: OrderStatus,
    time: Date
}

export interface OrderFilter {
    _id?: ObjectID,
    order_id?: string,
    trans_id?: string,
    user_id?: ObjectID,
    limit?: number,
    page?: number,
    role?: Role,
    tab?: OrderDisplayTab,
}

export enum OrderStatus {
    CREATED = 1,    //已下单,待付款
    DELIVING = 2,   //待发货,已付款
    RECEIPTING = 3, //待收货,已发货
    SUCCESS = 4,    //已完成,待评价
                    // 5预留
    CANCEL = 6,     //订单取消,未付款前可取消
    DELETED = 7,     //订单删除
}
export const OrderBuyerDisplayStatus = [
    '未定义', '待付款', '已付款', '待收货', '待评价', '未定义', '订单取消', '订单删除'
];

export enum OrderDisplayTab {ALL, CREATE, DELIVERY, RECEIPTING, EVALUATE}
export const OrderStatusByTab = {
    all      : {
        $nin : [
            OrderStatus.DELETED,
            OrderStatus.CANCEL
        ]
    } ,
    create  : OrderStatus.CREATED,
    delivery : OrderStatus.DELIVING,
    receipting : OrderStatus.RECEIPTING,
    evaluate : OrderStatus.SUCCESS
};

const OSta = OrderStatus;
const ASC = {};

export interface DirectPayParam{
    pay_type : PayType,

    subject : string,
    amount : number,
    trans_id : string,
}

export default class OrderModel extends BaseModel {
    name() {
        return 'OrderModel';
    }

    constructor(coll: Collection) {
        super(coll);
    }

    checkExist(filter: OrderFilter, role: Role): Promise<any> {
        let {_id, user_id} = filter;
        let match = {_id};
        switch (role) {
            case Role.BUYER:
                match['deleted.buyer'] = {'$ne': true};
                match['buyer.id'] = user_id;
                break;
            case Role.VENDOR:
                match['deleted.vendor'] = {'$ne': true};
                match['shop.id'] = user_id;
                break;
            default:
                break;
        }
        return this.findOne(new FindOneParam(match)).then((order: any) => {
            if (!order) {
                return Promise.resolve(null);
            }
            let prods = [];
            order.trans.products.forEach((prod) => {
                prods.push({id: prod.id, num: prod.num, name: prod.name,
                    thumb: prod.thumb, price: prod.price});
            });
            let result: Object;
            switch (role) {
                case Role.BUYER:
                    result = {
                        _id: order._id,
                        receiver: order.delivery.buyer,
                        buyer_log: order.trans.log,
                        trans: {
                            products: prods,
                            pay_type: '微信支付',
                            amount: order.trans.amount,
                            payment: order.trans.payment
                        },
                        time: utils.toDateString(order.time),
                    };
                    break;
                default:
            }
            return result;
        });
    }

    getOrders(filter:OrderFilter) {
        let {role, user_id, page, limit, tab} = filter;

        let match = {
            status: OrderStatusByTab[OrderDisplayTab[tab].toLowerCase()]
        };
        switch (role){
            case Role.BUYER:
                match['buyer.id'] = user_id;
                match['deleted.buyer'] = {'$ne': true};
                break;
            case Role.VENDOR:
                match['vendor.id'] = user_id;
                match['deleted.vendor'] = {'$ne': true};
                break;
            default: return Promise.reject({ err_code : ErrCode.ArgsInvalid });
        }
        let count = 0;
        return this.count(new CountParam(match)).then((totalCount) => {
            count = totalCount;

            let options = new FindParam(match, {
                status: 1,
                order_no: 1,
                trans: 1
            });
            options.limit = limit;
            options.skip = limit * page;
            options.sort = {'time': -1};
            return this.find(options);
        }).then((results) => {
            let orders = [];
            results.forEach((e) => {
                let prods = [];
                e.trans.products.forEach((prod) => {
                    prods.push({id: prod.id, num: prod.num, name: prod.name,
                        thumb: prod.thumb, price: prod.price});
                });
                orders.push({
                    id: e._id,
                    products: prods,
                    order_no: e.order_no,
                    payment: e.trans.payment,
                    status: OrderBuyerDisplayStatus[e.status]
                });
            });
            return {
                orders: orders,
                totalCount: count,
                totalPage: utils.ceil(count / limit)
            }
        });
    }

    createOrder(info: Order): Promise<any> {
        return this.insertOne(new InsertParam(info));
    }

    deliver(filter: OrderFilter): Promise<any> {
        let {_id, user_id} = filter;

        let match = {_id, 'vendor.id': user_id};
        let update = {
            '$set': {
                status: OrderStatus.RECEIPTING,
                'delivery.time': new Date(),
            },
            '$push': {audit_log: {
                from: OrderStatus.DELIVING,
                to: OrderStatus.RECEIPTING,
                time: new Date()
            }}
        };
        return this.updateOne(new UpdateParam(match, update));
    }

    receipt(filter: OrderFilter): Promise<any> {
        let {_id, user_id} = filter;

        let match = {_id, 'vendor.id': user_id};
        let update = {
            '$set': {
                status: OrderStatus.RECEIPTING,
                'delivery.time': new Date(),
            },
            '$push': {audit_log: {
                from: OrderStatus.DELIVING,
                to: OrderStatus.RECEIPTING,
                time: new Date()
            }}
        };
        return this.updateOne(new UpdateParam(match, update));
    }

    cancel(filter: OrderFilter): Promise<any> {
        let {_id, user_id} = filter;

        let match = {_id, 'buyer.id': user_id};
        let update = {
            '$set': {
                status: OrderStatus.CANCEL
            },
            '$push': {audit_log: {
                from: OrderStatus.CREATED,
                to: OrderStatus.CANCEL,
                time: new Date()
            }}
        };
        return this.updateOne(new UpdateParam(match, update));
    }

    deleteBuyer(filter: OrderFilter): Promise<any> {
        let {_id, user_id} = filter;

        let match = {_id, 'buyer.id': user_id};
        let update = {
            '$set': {
                'deleted.buyer': true,
            },
            '$push': {audit_log: {
                log: '买家删除',
                time: new Date()
            }}
        };
        return this.updateOne(new UpdateParam(match, update));
    }

    deleteVendor(filter: OrderFilter): Promise<any> {
        let {_id, user_id} = filter;

        let match = {_id, 'vendor.id': user_id};
        let update = {
            '$set': {
                'deleted.vendor': true,
            },
            '$push': {audit_log: {
                log: '卖家删除',
                time: new Date()
            }}
        };
        return this.updateOne(new UpdateParam(match, update));
    }
}
